home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1993 July / InfoMagic USENET CD-ROM July 1993.ISO / sources / unix / volume8 / fixcpio < prev    next >
Encoding:
Internet Message Format  |  1987-03-01  |  14.3 KB

  1. Subject:  v08i094:  Repair damaged "cpio -c" archives
  2. Newsgroups: mod.sources
  3. Approved: mirror!rs
  4.  
  5. Submitted by: rtech!daveb (Dave Brower)
  6. Mod.sources: Volume 8, Issue 94
  7. Archive-name: fixcpio
  8.  
  9. [  I wrote the Makefile.  --r$  ]
  10.  
  11. #! /bin/sh
  12. # This is a shell archive.  Remove anything before this line,
  13. # then unpack it by saving it in a file and typing "sh file".
  14. # If all goes well, you will see the message "End of shell archive."
  15. # Contents:  README Makefile fixcpio.1 fixcpio.c
  16. PATH=/bin:/usr/bin:/usr/ucb; export PATH
  17. echo shar: extracting "'README'" '(339 characters)'
  18. if test -f 'README' ; then 
  19.   echo shar: will not over-write existing file "'README'"
  20. else
  21. sed 's/^X//' >README <<'@//E*O*F README//'
  22. XTue Jan 27 12:22:37 PST 1987
  23. X
  24. XThis is a program for fixing broken cpio -c archives.  It is commonly
  25. Xused to recover a backup when disk 10 from a 30 disk archive has gotten
  26. Xtrashed.
  27. X
  28. XIt is often the "help" required by "Out of phase--get help."
  29. X
  30. XTo compile, either go:
  31. X
  32. X    cc -O fixcpio.c -o fixcpio
  33. X    
  34. Xor on System V say:
  35. X
  36. X    make fixcpio    
  37. X
  38. X-dB
  39. @//E*O*F README//
  40. if test 339 -ne "`wc -c <'README'`"; then
  41.     echo shar: error transmitting "'README'" '(should have been 339 characters)'
  42. fi
  43. fi # end of overwriting check
  44. echo shar: extracting "'Makefile'" '(249 characters)'
  45. if test -f 'Makefile' ; then 
  46.   echo shar: will not over-write existing file "'Makefile'"
  47. else
  48. sed 's/^X//' >Makefile <<'@//E*O*F Makefile//'
  49. Xfixcpio:    fixcpio.c
  50. X    $(CC) $(CFLAGS) -o fixcpio fixcpio.c
  51. X
  52. X# Edit appropriately.
  53. XDESTDIR    = /usr/local/bin
  54. XMANDIR    = /usr/man/man1
  55. XMANPAGE    = fixcpio.1
  56. Xinstall:    fixcpio
  57. X    cp fixcpio $(DESTDIR)
  58. X    strip $(DESTDIR)/fixcpio
  59. X    cp fixcpio.1 $(MANDIR)/$(MANPAGE)
  60. @//E*O*F Makefile//
  61. if test 249 -ne "`wc -c <'Makefile'`"; then
  62.     echo shar: error transmitting "'Makefile'" '(should have been 249 characters)'
  63. fi
  64. fi # end of overwriting check
  65. echo shar: extracting "'fixcpio.1'" '(2243 characters)'
  66. if test -f 'fixcpio.1' ; then 
  67.   echo shar: will not over-write existing file "'fixcpio.1'"
  68. else
  69. sed 's/^X//' >fixcpio.1 <<'@//E*O*F fixcpio.1//'
  70. X.\"    $Header: fixcpio.1,v 1.1 87/01/05 19:51:00 source Exp $
  71. X.TH FIXCPIO 1 "UNIX-PC" "Public Domain" "David Brower"
  72. X.ta 8n 16n 24n 32n 40n 48n 56n
  73. X.SH NAME
  74. Xfixcpio \- repair damaged cpio -c archives
  75. X.SH ORIGIN
  76. XDavid Brower, {gladys, sun, amdahl, mtxinu}!rtech!daveb
  77. X.SH SYNOPSIS
  78. X.B fixcpio
  79. X[ infile [ outfile ] ]
  80. X.SH DESCRIPTION
  81. X.I Fixcpio
  82. XReads the standard input (or the named \fIinfile\fP) and writes a cpio
  83. X-c archive to the standard output (or named \fIoutfile\fP).  
  84. X.I Infile
  85. Xand
  86. X.I outfile
  87. Xmay be the dash character (`\-') to signify standard in or out.
  88. X.PP
  89. XThe input is presumed to be a \fIcpio -c\fP archive.  While the input
  90. Xis copied to the output,
  91. X.I fixcpio
  92. Xchecks each archive member for sanity, and discards those that appear
  93. Xto be bad. The program writes the names of archive members copied on
  94. Xstderr, and says
  95. X.nf
  96. X
  97. X    Skipping bad member ``filename''
  98. X    
  99. X.fi
  100. Xfor each bad record.  This eliminates the cheerful ``Out of phase--get help''
  101. Xmessage from cpio.
  102. X.PP
  103. XThe major use for 
  104. X.I fixcpio
  105. Xis in recovering multiple floppy backups when one disk in the set goes
  106. Xbad.  The process for the UNIX-PC is about as follows.
  107. X
  108. X.PP
  109. X1.  Get images of the remaining floppies in files that are in alphabetical
  110. Xorder:
  111. X.nf
  112. X
  113. X    # works with up to 99 disk backup sets.
  114. X    #
  115. X    # if, ibs, and count will depend on your machine and
  116. X    # backup procedure.
  117. X    disk=01
  118. X    while :
  119. X    do
  120. X        echo "Interrupt to quit, return to read disk $disk \ec:"
  121. X        read answer
  122. X        dd if=/dev/rfp/021 ibs=1024 count=320 of=disk-$disk
  123. X        dismount -f
  124. X        disk=`awk "{ printf \e"%02d\en\e", $disk + 1 }" `
  125. X    done
  126. X
  127. X.fi
  128. X.PP
  129. X2.  Restore the contents of the disks with
  130. X.I fixcpio's
  131. Xhelp.
  132. X.nf
  133. X
  134. X    cat disk-* | fixcpio | cpio -icdum
  135. X
  136. X.fi
  137. X.SH FILES
  138. X.br
  139. X/tmp Holds a temp file containing the archive member currently being examined.
  140. X.SH BUGS
  141. X.I Fixcpio
  142. Xdoes not understand binary cpio archives.
  143. X.PP
  144. XGetting disk images from the floppies depends on both the machine and
  145. X    your backup procedures.  You need to know how the floppies are
  146. X    written before you start recovering, and this might be awkward if
  147. X    you've lost your hard disk.
  148. X.PP
  149. XUsing a temp file is a kludge, needed because you can't seek around on
  150. Xinput from a pipe.
  151. X.PP
  152. XStatus messages should probably be toggled with a -v `verbose' flag.
  153. @//E*O*F fixcpio.1//
  154. if test 2243 -ne "`wc -c <'fixcpio.1'`"; then
  155.     echo shar: error transmitting "'fixcpio.1'" '(should have been 2243 characters)'
  156. fi
  157. fi # end of overwriting check
  158. echo shar: extracting "'fixcpio.c'" '(9269 characters)'
  159. if test -f 'fixcpio.c' ; then 
  160.   echo shar: will not over-write existing file "'fixcpio.c'"
  161. else
  162. sed 's/^X//' >fixcpio.c <<'@//E*O*F fixcpio.c//'
  163. X
  164. X/*
  165. X**  fixcpio.c -- fix troubled cpio archive by skipping trashed members.
  166. X**
  167. X**  Dave Brower, 12/13/86
  168. X**  {sun, amdahl, mtxinu}!rtech!daveb
  169. X**
  170. X**  Usage:  fixcpio [ infile [ outfile ] ]
  171. X**
  172. X**  Writes a cpio -c archive to outfile (or stdout) from the infile (stdin).
  173. X**  ("-" may be used as the stdin/stdout filename.)
  174. X**
  175. X**  Skips over junk members.  This is how to recover when you've lost
  176. X**  floppy 9 of a 30 disk backup.  Eliminates "Out of phase -- get help"
  177. X*/
  178. X
  179. X# include <stdio.h>
  180. X
  181. X/* size blocks to write */
  182. X
  183. X# define BLKSIZ    512
  184. X
  185. X/* Maximum reasonable pathname in a header record */
  186. X
  187. X# define MAXPATH 128
  188. X
  189. Xtypedef struct
  190. X{
  191. X    /* these are ints for scanf's benefit. */
  192. X    int        h_magic,
  193. X            h_dev,
  194. X            h_ino,
  195. X            h_mode,
  196. X        h_uid,
  197. X        h_gid,
  198. X            h_nlink,
  199. X            h_rdev;
  200. X    long    h_longtime;
  201. X    int        h_namesize;
  202. X    long    h_longfile;
  203. X} CHARHDR;
  204. X
  205. Xtypedef struct
  206. X{
  207. X    CHARHDR    h;
  208. X    char     h_name[ MAXPATH ];
  209. X} CHARREC;
  210. X
  211. XCHARREC CRec = { 0 };            /* Character header */
  212. Xchar Trailer[] = "TRAILER!!!";        /* Magic string */
  213. Xchar Tmpfile[] = "/tmp/fixcpioXXXXXX";    /* temp file template */
  214. Xint Debug;                /* Debugging? */
  215. X
  216. Xvoid outerr();                /* error writing output file */
  217. Xvoid tmperr();                /* error writing temp file */
  218. Xvoid writeerr();            /* error writing file */
  219. Xint fprintf();                /* libc defined, -1 on error */
  220. X
  221. X/*
  222. X** main() -- fix a cpio archive with "Out of phase -- get help" problems.
  223. X*/
  224. Xmain(argc, argv)
  225. Xint argc;
  226. Xchar **argv;
  227. X{
  228. X    register int last;            /* last char processed */
  229. X    register int this;            /* current chars */
  230. X    register int nmagic;        /* "07"s in magic "070707" seen */
  231. X
  232. X    register FILE *ifp = stdin;        /* input stream */
  233. X    register FILE *ofp = stdout;    /* output stream */
  234. X    register FILE *tfp = NULL;        /* temp file */
  235. X
  236. X    int done = 0;            /* all done flag */
  237. X    long nbytes = 0;            /* count of bytes written */
  238. X
  239. X    char buf[ 512 ];            /* holds a trailer. */
  240. X
  241. X    char *getenv();            /* libc defined */
  242. X    FILE *efopen();            /* fopen, fatal on error */
  243. X    FILE *getmember();            /* stash a member in a temp file */
  244. X    long putmember();            /* write temp file */
  245. X
  246. X    /* Set "secret" debugging flag */
  247. X    Debug = getenv("FIXCPIO") != NULL;
  248. X
  249. X    if( argc > 3 )
  250. X    {
  251. X        fprintf(stderr, "Usage: fixcpio [ infile [ outfile ] ]\n");
  252. X    return( 1 );
  253. X    }
  254. X
  255. X    if( --argc > 0 && strcmp( *++argv, "-" ) )
  256. X    ifp = efopen( *argv, "r" );
  257. X
  258. X    if( --argc > 0 && strcmp( *++argv, "-" ) )
  259. X        ofp = efopen( *argv, "w" );
  260. X
  261. X    /*
  262. X    ** Process chars of input.  When you see a magic number, try
  263. X    ** to accumulate the archive member on a temp file.  Write out
  264. X    ** good members as they are validated, skipping trouble makers.
  265. X    */
  266. X    for ( nmagic = last = this = 0 ; !done ; last = this )
  267. X    {
  268. X    switch( this = getc( ifp ) )
  269. X    {
  270. X    case '0':
  271. X
  272. X        /* maybe a header, no special action */
  273. X        break;
  274. X
  275. X    case '7':
  276. X
  277. X        /* Maintain count of special "07" pairs */
  278. X        nmagic = last == '0' ? nmagic + 1 : 0;
  279. X
  280. X        /* It's a magic number, try to process as a header */
  281. X        if( nmagic == 3 )
  282. X        {
  283. X        nmagic = 0;
  284. X
  285. X        /* stashed entry is good, write it */
  286. X        if( tfp )
  287. X            nbytes += putmember( tfp, ofp );
  288. X
  289. X        /* stash this possible entry into tfp, get CRec */
  290. X        tfp = getmember( ifp );
  291. X        }
  292. X        break;
  293. X
  294. X    case EOF:
  295. X
  296. X        done = 1;
  297. X        /* Fall into... */
  298. X
  299. X    default:
  300. X
  301. X        /* Any existing entry is garbage... */
  302. X        nmagic = 0;
  303. X        if( tfp )
  304. X        {
  305. X        if( !strcmp( CRec.h_name, Trailer ) )
  306. X            done = 1;
  307. X        else
  308. X            fprintf(stderr, "Skipping bad member \"%s\"\n",
  309. X                CRec.h_name );
  310. X        (void)fclose( tfp );
  311. X        tfp = NULL;
  312. X        }
  313. X        break;
  314. X    } /* switch */
  315. X    } /* for */
  316. X
  317. X    /* flush pending good member */
  318. X    if( tfp )
  319. X    {
  320. X        nbytes += putmember( tfp, ofp );
  321. X    tfp = NULL;
  322. X    }
  323. X
  324. X    /* Write a trailer -- remember to terminate the name string! */
  325. X    (void)sprintf( buf,    "070707%06o%06o%06o%06o%06o%06o%06o%011o%06o%011o%s",
  326. X    0, 0, 0, 0, 0, 0, 0, 0, sizeof(Trailer) + 1, 0, Trailer );
  327. X    if( fprintf(ofp, "%s", buf) < 0  || putc( 0, ofp ) < 0 )
  328. X        outerr();
  329. X    nbytes += strlen( buf ) + 1;
  330. X
  331. X    /* round output to an even block */
  332. X    nbytes = BLKSIZ - (nbytes % BLKSIZ);
  333. X    while( nbytes-- )
  334. X        if( putc( 0, ofp ) < 0 )
  335. X        outerr();
  336. X
  337. X    if( fclose( ofp ) < 0 )
  338. X        outerr();
  339. X    return( 0 );
  340. X}
  341. X
  342. X/*
  343. X** getmember() -- save an archive member to a temp file
  344. X**
  345. X** When positioned after the magic number in a cpio file on ifp,
  346. X** copy the member to a temp file, and return it's fp.  The temp file
  347. X** contains a complete member (including magic number) and is positioned
  348. X** for catting directly to the real output file.
  349. X**
  350. X** If there are problems getting the member, return NULL.
  351. X*/
  352. XFILE *
  353. Xgetmember( ifp )
  354. Xregister FILE *ifp;
  355. X{
  356. X    register int c;            /* character of the member name */
  357. X    register int nr;            /* number read or scanned */
  358. X    register FILE *ofp;            /* temp file */
  359. X    long len;                /* actual member length */
  360. X
  361. X    char name[ sizeof(Tmpfile) + 1 ];    /* name of the temp file */
  362. X
  363. X    /* number of chars to read for a -c header */
  364. X#   define NCREAD    ( (8 * 6) + (2 * 11) )
  365. X
  366. X    char buf[ NCREAD + 1 ];        /* raw header */
  367. X
  368. X    char *mktemp();            /* libc, make temp file name */
  369. X    char *strcpy();            /* libc, copy string */
  370. X    long ncat();            /* cat file to a length */
  371. X
  372. X    if( NCREAD != ( nr = fread( buf, 1, NCREAD, ifp ) ) )
  373. X    {
  374. X    fprintf(stderr, "Couldn't read header:  Wanted %d, got %d\n",
  375. X        NCREAD, nr);
  376. X    return (NULL);
  377. X    }
  378. X
  379. X    if( Debug )
  380. X    {
  381. X    fprintf(stderr,
  382. X    "dev  |ino  |mode |uid  |gid  |nlink|rdev |longtime  |nsize|longfile\n" );
  383. X    fprintf(stderr, "%s\n", buf );
  384. X
  385. X    }
  386. X
  387. X    if( 10 != ( nr = sscanf( buf, "%6o%6o%6o%6o%6o%6o%6o%11o%6o%11o",
  388. X            &CRec.h.h_dev,  &CRec.h.h_ino,  &CRec.h.h_mode,
  389. X            &CRec.h.h_uid,  &CRec.h.h_gid,  &CRec.h.h_nlink,
  390. X            &CRec.h.h_rdev, &CRec.h.h_longtime,
  391. X            &CRec.h.h_namesize , &CRec.h.h_longfile ) ) )
  392. X    {
  393. X    fprintf(stderr, "Couldn't scan header:  Wanted 10, got %d\n", nr);
  394. X    return (NULL);
  395. X    }
  396. X
  397. X    if( Debug )
  398. X    {
  399. X     fprintf(stderr, "dev 0%o ino 0%o mode 0%o uid %d gid %d\n",
  400. X        CRec.h.h_dev, CRec.h.h_ino, CRec.h.h_mode,
  401. X        CRec.h.h_uid, CRec.h.h_gid );
  402. X     fprintf(stderr,
  403. X        "nlink %d rdev 0%o longtime 0%o namesize %d longfile 0%o\n",
  404. X        CRec.h.h_nlink, CRec.h.h_rdev, CRec.h.h_longtime,
  405. X        CRec.h.h_namesize, CRec.h.h_longfile );
  406. X    }
  407. X
  408. X    /* Ridiculous name size?  probably trashed entry */
  409. X    if( !CRec.h.h_namesize || CRec.h.h_namesize > sizeof( CRec.h_name ) )
  410. X    {
  411. X    fprintf(stderr, "Bad namesize %d\n", CRec.h.h_namesize );
  412. X        return (NULL);
  413. X    }
  414. X
  415. X    /* Get the name */
  416. X    nr = 0;
  417. X    while( nr < CRec.h.h_namesize && ( c = getc( ifp ) ) != EOF )
  418. X        CRec.h_name[ nr++ ] = c;
  419. X
  420. X    if( c == EOF )
  421. X    {
  422. X    fprintf(stderr, "Unexpected EOF reading name in header\n");
  423. X        return (NULL);
  424. X    }
  425. X
  426. X    if( Debug )
  427. X    fprintf(stderr, "name \"%s\"\n", CRec.h_name );
  428. X
  429. X    /* create a new temp file, and mark it for delete on close */
  430. X    (void)strcpy( name, mktemp( Tmpfile ) );
  431. X    ofp = efopen( name, "w+" );
  432. X    (void)unlink( name );
  433. X
  434. X    /* Write a header */
  435. X    fprintf( ofp, "070707%06o%06o%06o%06o%06o%06o%06o%011o%06o%011o",
  436. X                CRec.h.h_dev,  CRec.h.h_ino,  CRec.h.h_mode,
  437. X            CRec.h.h_uid,  CRec.h.h_gid,  CRec.h.h_nlink,
  438. X            CRec.h.h_rdev,  CRec.h.h_longtime,
  439. X            CRec.h.h_namesize, CRec.h.h_longfile ) ;
  440. X
  441. X    for( nr = 0; nr < CRec.h.h_namesize ; )
  442. X        putc( CRec.h_name[ nr++ ], ofp );
  443. X
  444. X    /* now copy the file body */
  445. X    if( CRec.h.h_longfile != (len = ncat( CRec.h.h_longfile, ifp, ofp ) ) )
  446. X    {
  447. X    fprintf(stderr, "Bad member length:  Should be %ld, was %ld\n",
  448. X        CRec.h.h_longfile, len );
  449. X    (void)fclose( ofp );
  450. X    return( NULL );
  451. X    }
  452. X
  453. X    if( fseek( ofp, 0L, 0 ) < 0L )
  454. X        tmperr();
  455. X    return( ofp );
  456. X
  457. X}
  458. X
  459. X/*
  460. X** putmember() -- Write member, close input and return bytes written
  461. X*/
  462. Xlong
  463. Xputmember( ifp, ofp )
  464. Xregister FILE * ifp;
  465. Xregister FILE * ofp;
  466. X{
  467. X    register long n;
  468. X    long cat();
  469. X
  470. X    fprintf(stderr, "%s\n", CRec.h_name );
  471. X    n = cat( ifp, ofp );
  472. X    (void)fclose( ifp );
  473. X    return ( n );
  474. X}
  475. X
  476. X
  477. X
  478. X/*
  479. X** cat() -- copy one stream to another, returning n bytes copied
  480. X*/
  481. Xlong
  482. Xcat( ifp, ofp )
  483. Xregister FILE *ifp;
  484. Xregister FILE *ofp;
  485. X{
  486. X    register int c;
  487. X    register int n;
  488. X
  489. X    for( n = 0 ; ( c = getc( ifp ) ) != EOF ; n++ )
  490. X        if( putc( c, ofp ) < 0 )
  491. X        outerr();
  492. X
  493. X    return ( n );
  494. X}
  495. X
  496. X/*
  497. X** ncat() -- copy up to n bytes from one stream to another, return actual
  498. X*/
  499. Xlong
  500. Xncat( in, ifp, ofp )
  501. Xregister long in;
  502. Xregister FILE *ifp;
  503. Xregister FILE *ofp;
  504. X{
  505. X    register int c;
  506. X    register long on;
  507. X
  508. X    for( on = 0; in-- && ( c = getc( ifp ) ) != EOF ; on++ )
  509. X        if( putc( c, ofp ) < 0 )
  510. X        tmperr();
  511. X
  512. X    return ( on );
  513. X}
  514. X
  515. X/*
  516. X** efopen() -- fopen() that fatals on error
  517. X*/
  518. XFILE *
  519. Xefopen( file, mode )
  520. Xchar *file;
  521. Xchar *mode;
  522. X{
  523. X    FILE * fp;
  524. X
  525. X    if( NULL == (fp = fopen( file, mode ) ) )
  526. X    {
  527. X    fprintf(stderr, "Can't open \"%s\" mode \"%s\"\n", file, mode );
  528. X    perror("efopen");
  529. X    exit( 1 );
  530. X    }
  531. X    return( fp );
  532. X}
  533. X
  534. X/*
  535. X** outerr() -- handle error writing output file
  536. X*/
  537. Xvoid
  538. Xouterr()
  539. X{
  540. X    writeerr( "output" );
  541. X}
  542. X
  543. X/*
  544. X** tmperr() -- handle error writing temp file
  545. X*/
  546. Xvoid
  547. Xtmperr()
  548. X{
  549. X    writeerr( "temp" );
  550. X}
  551. X
  552. X/*
  553. X** writeerr() -- handle write errors, gracelessly.
  554. X*/
  555. Xvoid
  556. Xwriteerr( what )
  557. Xchar *what;
  558. X{
  559. X    fprintf(stderr, "\007Error writing %s file", what );
  560. X    perror("");
  561. X
  562. X}
  563. X
  564. X/* end of fixcpio.c */
  565. @//E*O*F fixcpio.c//
  566. if test 9269 -ne "`wc -c <'fixcpio.c'`"; then
  567.     echo shar: error transmitting "'fixcpio.c'" '(should have been 9269 characters)'
  568. fi
  569. fi # end of overwriting check
  570. echo shar: "End of shell archive."
  571. exit 0
  572.